/**
 * @project heima-leadnews
 * @author MECHREVO
 * @date 2024/1/18 14:16:57
 * @version 1.0
 */
package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.heima.common.exception.CustomException;
import com.heima.fegin.article.IArticleClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.BaiduScanService;
import com.heima.wemedia.service.WmAutoScanService;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.Tesseract;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@Async
public class WmAutoScanServiceImpl implements WmAutoScanService {
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private BaiduScanService baiduScanService;
    @Autowired
    private IArticleClient iArticleClient;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Override
    public void autoScan(Integer newsId) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        WmNews wmNews=wmNewsMapper.selectById(newsId);
        if(wmNews==null || wmNews.getStatus()!=WmNews.Status.SUBMIT.getCode()){

            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 处理文本和图片，并返回包含文本和图片的映射表
        Map<String, Object> textAndImg = handleTextAndImg(wmNews);

        // 扫描文本是否成功
        boolean isTextScan = scanText(textAndImg.get("text"), wmNews);
        if (!isTextScan) return;

        // 扫描图片是否成功
        boolean isImgScan = scanImg((HashSet<String>) textAndImg.get("img"), wmNews);
        if (!isImgScan) return;

        // 保存文章
        saveArticle(wmNews);

    }

    private void saveArticle(WmNews wmNews) {
        ArticleDto articleDto = new ArticleDto();  // 创建ArticleDto对象
        BeanUtils.copyProperties(wmNews, articleDto);  // 将wmNews对象的属性复制到articleDto对象中
        Long aid = wmNews.getArticleId();  // 获取wmNews对象的articleId
        if (aid != null) {  // 如果articleId不为空
            articleDto.setId(aid);  // 将articleId赋值给articleDto对象的id属性
        }
        articleDto.setAuthorId(wmNews.getUserId().longValue());  // 将wmNews对象的userId转换为long类型并赋值给articleDto对象的authorId属性
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());  // 根据userId查询WmUser对象
        if (wmUser != null) {  // 如果查询到的WmUser对象不为空
            articleDto.setAuthorName(wmUser.getName());  // 将WmUser对象的name赋值给articleDto对象的authorName属性
        }
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());  // 根据channelId查询WmChannel对象
        if (wmChannel != null) {  // 如果查询到的WmChannel对象不为空
            articleDto.setChannelName(wmChannel.getName());  // 将WmChannel对象的name赋值给articleDto对象的channelName属性
        }
        articleDto.setLayout(wmNews.getType());  // 将wmNews对象的type赋值给articleDto对象的layout属性
        ResponseResult result = iArticleClient.saveArticle(articleDto);  // 调用iArticleClient对象的saveArticle方法保存articleDto对象
        if (result.getCode() == 200) {  // 如果保存成功（返回码为200）
            String articleId = result.getData().toString();  // 获取保存成功后的articleId
            wmNews.setArticleId(Long.valueOf(articleId));  // 将articleId转换为Long类型并赋值给wmNews对象的articleId
            updateNewsStatus(wmNews, WmNews.Status.PUBLISHED, "审核成功");  // 更新wmNews对象的状态为已发布和审核成功
        }

    }

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private Tesseract tesseract;

    private boolean scanImg(HashSet<String> imgs, WmNews wmNews) {
        for (String img : imgs) {
            //使用tess4j进行ocr图文识别，将图片中的文字提取出来进行文本审核
            byte[] bytes = fileStorageService.downLoadFile(img);
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            BufferedImage bufferedImage = null;
            try {
                bufferedImage = ImageIO.read(bis);
                String textInImg = tesseract.doOCR(bufferedImage);
                boolean flag = scanText(textInImg, wmNews);
                if (!flag) return flag;
            } catch (Exception e) {
                e.printStackTrace();
            }
            //调用百度云接口审核
            Map<String, Object> resMap = baiduScanService.scanImg(img);
            Integer conclusionTyp = Integer.valueOf(resMap.get("conclusionType").toString());
            if (conclusionTyp == 2 || conclusionTyp == 4) {
                updateNewsStatus(wmNews, WmNews.Status.FAIL, "审核失败：图片内容违规");
                return false;
            } else if (conclusionTyp == 3) {
                updateNewsStatus(wmNews, WmNews.Status.ADMIN_AUTH, "待人工审核，图片内容疑似违规");
                return false;
            }
        }
        return true;
    }

      private void updateNewsStatus(WmNews wmNews, WmNews.Status fail, String reason) {
        wmNews.setStatus(fail.getCode());
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }
    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    private boolean scanText(Object text, WmNews wmNews) {
        String sensitivesJSON = redisTemplate.opsForValue().get("Sensitives");
        if(StringUtils.isEmpty(sensitivesJSON)){
            //先内审--查看文章是否包含WmSensitive中的内容
            List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
            List<String> collect = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
            sensitivesJSON = JSON.toJSONString(collect);
            redisTemplate.opsForValue().set("Sensitives",sensitivesJSON);
        }
        //初始化敏感词字典
        List collect = JSON.parseObject(sensitivesJSON, List.class);
        SensitiveWordUtil.initMap(collect);
        //基于字典来匹配文本中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text.toString());
        if(map!=null&&map.size()>0){
            updateNewsStatus(wmNews, WmNews.Status.FAIL, "审核失败：文本内容违规");
            return false;
        }
        //在外审--调用百度云接口审核
        Map<String, Object> resMap=baiduScanService.scanText(text.toString());
        Integer conclusionTyp = Integer.valueOf(resMap.get("conclusionType").toString());
        if(conclusionTyp ==2 || conclusionTyp==4){
            updateNewsStatus(wmNews, WmNews.Status.FAIL, "审核失败：文本内容违规");
            return false;
        }else if(conclusionTyp==3){
            updateNewsStatus(wmNews, WmNews.Status.ADMIN_AUTH, "待人工审核，文本内容疑似违规");
            return false;
        }
        return true;
    }

    private Map<String, Object> handleTextAndImg(WmNews wmNews) {
        StringBuilder textContainer=new StringBuilder(wmNews.getTitle());
        HashSet<String> imgContainer=new HashSet<>();
        String contentStr = wmNews.getContent();
        JSONArray jsonArray= JSON.parseArray(contentStr);
        for (Object obj : jsonArray) {
            JSONObject jsonObject = JSONObject.parseObject(obj.toString());
            if("text".equals(jsonObject.getString("type"))){
            textContainer.append(jsonObject.getString("value"));
            }else {
                imgContainer.add(jsonObject.getString("value"));
            }
        }
        textContainer.append(wmNews.getLabels());
        Map<String,Object>res=new HashMap<>();
        res.put("text",textContainer.toString());
        res.put("img",imgContainer);
        return res;
    }
}
